//
//  NSObject+Blocks.m
//  PSFoundation
//
//  Created by Peter Steinberger on 24.10.10.
//  Copyright 2010 Peter Steinberger. All rights reserved.
//

#import "NSObject+Blocks.h"
#import <dispatch/dispatch.h>
#import <objc/runtime.h>

static inline dispatch_time_t dTimeDelay(NSTimeInterval time) {
    int64_t delta = (int64_t)(NSEC_PER_SEC * time);
    return dispatch_time(DISPATCH_TIME_NOW, delta);
}

@implementation NSObject (Blocks)


-(void)performAfterBlock:(dispatch_block_t)block after:(float)time
{
    dispatch_after(dTimeDelay(time), dispatch_get_main_queue(), ^{
        block();
    });
}

- (void)performBlock:(void (^)(void))block
          afterDelay:(NSTimeInterval)delay
{
    block = [block copy];
    [self performSelector:@selector(fireBlockAfterDelay:)
               withObject:block
               afterDelay:delay];
}

- (void)fireBlockAfterDelay:(void (^)(void))block {
    block();
}

- (void)performAfterDelay:(float)delay thisBlock:(void (^)(BOOL finished))completion{
    
    [UIView animateWithDuration:delay
                     animations: ^{
                         
                     }completion:^(BOOL finished) {
                         
                         if (completion) {
                             completion(finished);
                         }
                     }];
}




- (void)performBlockInBackground:(NSObjectPerformBlock)performBlock completion:(NSObjectPerformBlock)completionBlock userObject:(id)userObject
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        performBlock(userObject);
        dispatch_async(dispatch_get_main_queue(), ^{
            if (completionBlock) {
                completionBlock(userObject);
            }
        });
    });
}


- (void)countdDown:(NSInteger)timeOut Done:(dispatch_block_t)done Time:(void(^)(NSInteger Count))time {
    __block int timeout = (int)timeOut;
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
    dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0);
    dispatch_source_set_event_handler(_timer, ^{
        if(timeout <= 0){
            dispatch_source_cancel(_timer);
            dispatch_async(dispatch_get_main_queue(), ^{
                done();
            });
        }else{
            dispatch_async(dispatch_get_main_queue(), ^{
                time(timeout);
            });
        }
        timeout--;
    });
    dispatch_resume(_timer);
}



- (void)performOnMainThread:(void(^)(void))block wait:(BOOL)shouldWait {
    if (shouldWait) {
        // Synchronous
        dispatch_sync(dispatch_get_main_queue(), block);
    }
    else {
        // Asynchronous
        dispatch_async(dispatch_get_main_queue(), block);
    }
}
- (void)performAsynchronous:(void(^)(void))block {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, block);
}
- (void)performAfter:(NSTimeInterval)seconds block:(void(^)(void))block {
    dispatch_after(dTimeDelay(seconds), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), block);
}


@end



@implementation NSObject (Category)

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg1 withObject:(id)arg2 waitUntilDone:(BOOL)wait {
    NSMethodSignature *signature = [self methodSignatureForSelector:aSelector];
    if (!signature) {
        return;
    }
    
    NSInvocation *invo = [NSInvocation invocationWithMethodSignature:signature];
    [invo setTarget:self];
    [invo setSelector:aSelector];
    [invo setArgument:&arg1 atIndex:2];
    [invo setArgument:&arg2 atIndex:3];
    [invo retainArguments];
    [invo performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:wait];
}

- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg1 withObject:(id)arg2 {
    NSMethodSignature *signature = [self methodSignatureForSelector:aSelector];
    if (!signature) {
        return;
    }
    
    NSInvocation *invo = [NSInvocation invocationWithMethodSignature:signature];
    [invo setTarget:self];
    [invo setSelector:aSelector];
    [invo setArgument:&arg1 atIndex:2];
    [invo setArgument:&arg2 atIndex:3];
    [invo retainArguments];
    
    [invo performSelectorInBackground:@selector(invoke) withObject:nil];
}

@end


